/**
 * @class wosh::UserInfoCommmunicators   
 * @brief  
 *
 ****************************************************************************
 * @version $Id: UserInfoCommmunicators.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR UserS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_UserInfoCommmunicators_H__
 #define __WOSH_Core_UserInfoCommmunicators_H__

 #include <woshDefs.h>
 #include <core/Containers.h>
 #include <core/Serialization.h>


namespace wosh {

struct UserInfoCommmunicatorData {
	long timestamp;		///< negative means user is actually offline (seen at abs(value))
	double ranking;		///< [0,[
};

class UserInfoCommmunicators : public virtual ISerializable
 {
	WOSH_SERIALIZABLE(wosh::UserInfoCommmunicators)
	WOSH_COMPARE_RTTI(wosh::UserInfoCommmunicators)

	typedef MapT<std::string, UserInfoCommmunicatorData> tStrUserInfoCommmunicatorDataMap;


	public:

		UserInfoCommmunicators() { }

		UserInfoCommmunicators( const UserInfoCommmunicators& m ) {
			*this = m;
		 }

		virtual ~UserInfoCommmunicators() { }


//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:

		void update( const std::string& communicator, UserInfoCommmunicatorData info ) {
			this->communicators.transactionBeginWrite();
			this->communicators.set(communicator, info);
			this->communicators.transactionEnd();
		 }

		void update( const std::string& communicator, long timestamp, double ranking ) {
			this->communicators.transactionBeginWrite();
			UserInfoCommmunicatorData info;
			info.timestamp = timestamp;
			info.ranking = ranking;
			this->communicators.set(communicator, info);
			this->communicators.transactionEnd();
		 }

		///< updates only ranking when exists, else set ranking to 0
		void updateTimeStampOf( const std::string& communicator, long timestamp ) {
			this->communicators.transactionBeginWrite();
			UserInfoCommmunicatorData info;
			info.ranking = 0;
			if ( this->communicators.exists(communicator) )
				info = this->communicators.find(communicator);
			info.timestamp = timestamp;
			this->communicators.set(communicator, info);
			this->communicators.transactionEnd();
		 }

		///< updates only ranking when exists, else set timestamp to 0
		void updateRankingOf( const std::string& communicator, double ranking, bool offset = false ) {
			this->communicators.transactionBeginWrite();
			UserInfoCommmunicatorData info;
			info.timestamp = 0;
			info.ranking = 0;
			if ( this->communicators.exists(communicator) )
				info = this->communicators.find(communicator);
			if ( offset ) {
				info.ranking += ranking;
				if ( info.ranking < 0 ) info.ranking = 0;
				//if ( info.ranking > 1.0 ) info.ranking = 1.0;
			 }
			else
				info.ranking = ranking;
			this->communicators.set(communicator, info);
			this->communicators.transactionEnd();
		 }

		void filterTimedOut( long epoch ) {
			this->communicators.transactionBeginWrite();
			tStrUserInfoCommmunicatorDataMap::Iterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = this->communicators.end();
			for ( it=this->communicators.begin(); it!=it_end; ++it ) {
				if ( it->second.timestamp >= epoch ) continue;
				this->communicators.erase(it);
			 }
			this->communicators.transactionEnd();
		 }


//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:

		tStrUserInfoCommmunicatorDataMap& getCommmunicators()					{ return this->communicators; }
		const tStrUserInfoCommmunicatorDataMap& getCommmunicators() const		{ return this->communicators; }

		void getCommmunicatorLast( std::string& communicator, UserInfoCommmunicatorData& info ) const {
			communicator = "";
			info.timestamp = LIMIT_LONG_MIN;
			info.ranking = 0;
			this->communicators.transactionBeginRead();
			tStrUserInfoCommmunicatorDataMap::ConstIterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = this->communicators.end();
			for ( it=this->communicators.begin(); it!=it_end; ++it ) {
				if ( it->second.timestamp > info.timestamp ) continue;
				communicator = it->first;
				info = it->second;
			 }
			this->communicators.transactionEnd();
		 }

		std::string getLastName() const {
			std::string communicator = ""; UserInfoCommmunicatorData commData;
			getCommmunicatorLast( communicator, commData );
			return communicator;
		 }

		UserInfoCommmunicatorData getLastData() const {
			std::string communicator = ""; UserInfoCommmunicatorData commData;
			getCommmunicatorLast( communicator, commData );
			return commData;
		 }

		void getCommmunicatorRank( std::string& communicator, UserInfoCommmunicatorData& info ) const {
			communicator = "";
			info.ranking = -1;
			info.timestamp = LIMIT_LONG_MIN;
			this->communicators.transactionBeginRead();
			tStrUserInfoCommmunicatorDataMap::ConstIterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = this->communicators.end();
			for ( it=this->communicators.begin(); it!=it_end; ++it ) {
				if ( it->second.ranking < info.ranking ) continue;
				if ( it->second.ranking == info.ranking && it->second.timestamp < info.timestamp ) continue;
				communicator = it->first;
				info = it->second;
			 }
			this->communicators.transactionEnd();
		 }

		double getLowestRanking( double minvalue ) const {
			double value = 100000;
			MutexLockerRead mL(this->communicators.getMutex());
			tStrUserInfoCommmunicatorDataMap::ConstIterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = this->communicators.end();
			for ( it=this->communicators.begin(); it!=it_end; ++it ) {
				if ( it->second.ranking < minvalue ) continue;
				if ( it->second.ranking >= value ) continue;
				value = it->second.ranking;
			 }
			if ( value == 100000 )
				return minvalue;
			return value;
		 }

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual UserInfoCommmunicators& operator=(const UserInfoCommmunicators& m) {
			m.communicators.transactionBeginRead();
			this->communicators.transactionBeginWrite();
			tStrUserInfoCommmunicatorDataMap::ConstIterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = m.communicators.end();
			for ( it=m.communicators.begin(); it!=it_end; ++it ) {
				this->communicators.set( it->first, it->second );
			 }
			this->communicators.transactionEnd();
			m.communicators.transactionEnd();
			return *this;
		 }

		virtual bool operator==(const UserInfoCommmunicators &other) const {
			if ( this->communicators.count() != other.communicators.count() )
				return false;
			return false;
		 }

		virtual bool operator!=(const UserInfoCommmunicators &other) const	{ return !(*this == other);  }

//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const			{ return ""; }
		virtual bool updateHash( DataHashContext* hash_context ) const {
			if ( hash_context == NULL ) return false;
			bool ret = true;
			tStrUserInfoCommmunicatorDataMap::ConstIterator it;
			const tStrUserInfoCommmunicatorDataMap::ConstIterator it_end = this->communicators.end();
			for ( it=this->communicators.begin(); it!=it_end; ++it ) {
				ret = hash_context->update( it->first ) & ret;
				ret = hash_context->update( it->second.timestamp ) & ret;
				ret = hash_context->update( it->second.ranking ) & ret;
			 }
			return ret;
		 }
//@}
	protected:
		tStrUserInfoCommmunicatorDataMap communicators;	///< commmunicators

}; // class def

}; // namespace wosh

#endif //__WOSH_Core_UserInfoCommmunicators_H__
